package cn.wmw.xyy.service.impl;

import cn.wmw.result.JsonResult;
import cn.wmw.xyy.doc.CourseDoc;
import cn.wmw.xyy.domain.*;
import cn.wmw.xyy.dto.CourseDto;
import cn.wmw.xyy.exception.GlobalExceptionEnum;
import cn.wmw.xyy.feign.EsCourseFeignClient;
import cn.wmw.xyy.feign.MediaFeignClient;
import cn.wmw.xyy.mapper.CourseMapper;
import cn.wmw.xyy.service.*;
import cn.wmw.xyy.utils.AssertUtil;
import cn.wmw.xyy.vo.CourseDetailVo;
import cn.wmw.xyy.vo.CourseInfoVo;
import cn.wmw.xyy.vo.CourseOrderInfoVo;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wmw
 * @since 2022-12-31
 */
@Service
@Slf4j
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {

    @Autowired
    private ITeacherService teacherService;

    @Autowired
    private ICourseDetailService courseDetailService;

    @Autowired
    private ICourseMarketService courseMarketService;

    @Autowired
    private ICourseResourceService courseResourceService;

    @Autowired
    private CourseMapper courseMapper;

    @Autowired
    private EsCourseFeignClient esCourseFeignClient;


    @Autowired
    private ICourseSummaryService courseSummaryService;

    @Autowired
    private ICourseTypeService courseTypeService;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private ICourseChapterService courseChapterService;


    @Autowired
    private MediaFeignClient mediaFeignClient;


    @Override
    public void saveAll(CourseDto courseDto) {
        //参数校验json303
        //业务校验
        Course course = courseDto.getCourse();
        log.info(course.getPic());
        CourseDetail courseDetail = courseDto.getCourseDetail();
        CourseMarket courseMarket = courseDto.getCourseMarket();
        CourseResource courseResource = courseDto.getCourseResource();
        List<Long> teacherIds = courseDto.getTeacherIds();
        // 1.查课程是否已经存在，存在抛异常，不允许新增
        getCourse(course.getName());
        // 2.存课程（课程表t_course），获取返回的主键id
        saveCourse(course, teacherIds);
        Long courseId = course.getId();
        // 3.存课程详情表（t_course_detail）
        saveCourseDetail(courseId, courseDetail);
        // 4.存课程销售表（t_course_market）
        saveCourseMarket(courseMarket, courseId);
        // 5. 存课件表（t_course_resource）
        saveCourseResource(courseResource, courseId);
        // 6. 存课程教师中间表（t_course_teacher）
        courseMapper.insertCourseTeacher(courseId,teacherIds);


    }

    @Override
    public void onLineCourse(Long courseId) {

        Course course = selectById(courseId);
        AssertUtil.isNotNull(course, GlobalExceptionEnum.ERROR);
        AssertUtil.isEquals(Course.OFFLINE.toString(), course.getStatus().toString(), GlobalExceptionEnum.ERROR);

        // 存ES
        saveEsCourseDoc(course);
        // 修改课程状态
        course.setStatus(Course.ONLINE);
        course.setOnlineTime(new Date());
        updateById(course);
        // 推送课程信息
        Message<Course> message = MessageBuilder.withPayload(course).build();
        rocketMQTemplate.sendOneWay("course-topic:sendMessage-tag", message);
    }

    @Override
    public CourseDetailVo detailData(Long id) {
        // 1.业务校验
        Course course = selectById(id);
        AssertUtil.isNotNull(course, GlobalExceptionEnum.ERROR);
        AssertUtil.isEquals(Course.ONLINE.toString(), course.getStatus().toString(), GlobalExceptionEnum.ERROR);
        // 2.封装数据
        CourseMarket courseMarket = courseMarketService.selectById(id);
        CourseDetail courseDetail = courseDetailService.selectById(id);
        CourseSummary courseSummary = courseSummaryService.selectById(id);
        List<Teacher> teachers = courseMapper.selectTeachersByCourseId(id);
        List<CourseChapter> courseChapters = selectCourseChaptersByCourseId(id);

        CourseDetailVo courseDetailVo = new CourseDetailVo();
        courseDetailVo.setCourse(course);
        courseDetailVo.setCourseChapters(courseChapters);
        courseDetailVo.setCourseDetail(courseDetail);
        courseDetailVo.setCourseMarket(courseMarket);
        courseDetailVo.setCourseSummary(courseSummary);
        courseDetailVo.setTeachers(teachers);
        return courseDetailVo;
    }

    /**
     *
     * 获取订单页课程信息
     * @param courseId
     * @return
     */
    @Override
    public CourseOrderInfoVo info(String courseId) {

        String[] split = courseId.split(",");
        AssertUtil.isTrue(split.length > 0 ,GlobalExceptionEnum.ERROR);
        String pattern = "^[1-9]d*$";// todo 正则验证可以用写到配置文件
        Set<Long> ids = Arrays.stream(split).filter(e -> !e.matches(pattern)).map(Long::valueOf).collect(Collectors.toSet());
        AssertUtil.isTrue(ids.size() == split.length,GlobalExceptionEnum.ERROR);
        //所有课程
        List<Course> courses = selectBatchIds(ids);
        AssertUtil.isTrue(courses.size() > 0 ,GlobalExceptionEnum.ERROR);
        List<Course> courseList = courses.stream().filter(e -> e.getStatus().equals(Course.OFFLINE)).collect(Collectors.toList());
        //唯一主键关联，查询market
        Map<Long, CourseMarket> marketMap = courseMarketService.selectBatchIds(ids).stream().collect(Collectors.toMap(CourseMarket::getId, courseMarket -> courseMarket));
        List<CourseInfoVo> courseInfos = new ArrayList<>();
        CourseOrderInfoVo courseOrderInfoVo = new CourseOrderInfoVo();
        BigDecimal totalAmount = new BigDecimal(0.0);
        //遍历courses集合，将数据装入CourseOrderInfoVo
        for (Course course:courses){
            CourseInfoVo courseInfoVo = new CourseInfoVo();
            courseInfoVo.setCourse(course);
            CourseMarket courseMarket = marketMap.get(course.getId());
            courseInfoVo.setCourseMarket(courseMarket);
            courseInfos.add(courseInfoVo);
            totalAmount = totalAmount.add(courseMarket.getPrice());
        }
        courseOrderInfoVo.setCourseInfos(courseInfos);
        courseOrderInfoVo.setTotalAmount(totalAmount);
        return courseOrderInfoVo;
    }

    private List<CourseChapter> selectCourseChaptersByCourseId(Long id) {
        // 1.根据课程Id查询所有章节
        List<CourseChapter> courseChapters = courseChapterService.listByCourseId(id);
        // 2.根据课程Id查询课程的所有视频
        JsonResult jsonResult = mediaFeignClient.getMediaFileByCourseId(id);
        AssertUtil.isTrue(jsonResult.isSuccess(), GlobalExceptionEnum.ERROR);
        AssertUtil.isNotNull(jsonResult.getData(), GlobalExceptionEnum.ERROR);
        List<MediaFile> mediaFiles = JSON.parseArray(JSON.toJSONString(jsonResult.getData()), MediaFile.class);
        // 3.为了减少双重for循环，将课程章节集合转换为map
        Map<Long, CourseChapter> courseChapterMap = courseChapters.stream().collect(Collectors.toMap(CourseChapter::getId, courseChapter -> courseChapter));
        // 4.根据每个mediaFile的chapterId找到自己的chapter对象，放入到chapter对象的mediaFile集合中
        mediaFiles.forEach(e -> {
                    e.setFileUrl("");
                    courseChapterMap.get(e.getChapterId()).getMediaFiles().add(e);
                }
        );
        // 5.返回组装好的章节集合数据
        return courseChapters;
    }

    private void saveEsCourseDoc(Course course) {
        CourseDoc courseDoc = new CourseDoc();

        Long courseId = course.getId();
        BeanUtils.copyProperties(course, courseDoc);

        CourseMarket courseMarket = courseMarketService.selectById(courseId);
        BeanUtils.copyProperties(courseMarket, courseDoc);
        String chargeName = 1 == courseMarket.getCharge() ? "免费" : "收费";
        courseDoc.setChargeName(chargeName);

        CourseSummary courseSummary = courseSummaryService.selectById(courseId);
        BeanUtils.copyProperties(courseSummary, courseDoc);

        CourseType courseType = courseTypeService.selectById(course.getCourseTypeId());
        courseDoc.setTypeName(courseType.getName());
        courseDoc.setTotalCount(courseType.getTotalCount());

        JsonResult save = esCourseFeignClient.saveOrUpdate(courseDoc);
        AssertUtil.isTrue(save.isSuccess(), GlobalExceptionEnum.ERROR);
    }

    private void saveCourseResource(CourseResource courseResource, Long courseId) {
        courseResource.setCourseId(courseId);
        courseResourceService.insert(courseResource);
    }

    /**
     * 存入课程销售表
     * @param courseMarket
     * @param courseId
     */
    private void saveCourseMarket(CourseMarket courseMarket, Long courseId) {
        courseMarket.setId(courseId);
        if (courseMarket.getPrice() == null){
            courseMarket.setPrice(CourseMarket.FREE);
        }
        courseMarketService.insert(courseMarket);
    }

    /**
     * 存入课程详情表
     * @param courseId
     * @param courseDetail
     */
    private void saveCourseDetail(Long courseId, CourseDetail courseDetail) {
        courseDetail.setId(courseId);
        courseDetailService.insert(courseDetail);
    }

    /**
     * 存入课程表
     * @param course
     * @param teacherIds
     */
    private void saveCourse(Course course, List<Long> teacherIds) {
        course.setStatus(Course.OFFLINE);
        course.setLoginId(8L);
        course.setLoginUserName("terry");
        String collect = teacherService.selectBatchIds(teacherIds).stream().map(Teacher::getName)
                                            .collect(Collectors.joining(","));
        course.setTeacherNames(collect);
        insert(course);
    }

    /**
     * 判断课程是否已存在
     * @param name
     */
    private void getCourse(String name) {
        Wrapper<Course> wrapper = new EntityWrapper<>();
        wrapper.eq("name", name);
        Course selectOne = selectOne(wrapper);
        AssertUtil.isNull(selectOne, GlobalExceptionEnum.ERROR);
    }
}
